#ifndef _SCHEDULER_H
#define _SCHEDULER_H

#include "shell.h"
#include "defs.h"

#define SEGMENT_SIZE 4096
#define PAGE_SIZE 4096
#define STACK_PAGE_BEGIN 0x00400000
#define STACK_PAGE_NEXT  0x00001000
#define MIN_PRIORITY 1


typedef enum { KILLED, RUNNING, READY, BLOCKED, WAITCHILD, SLEEPING } statusT;

/*
 * Tipo de datos: segmentT
 * -----------------------
 * Arreglo que define el espacio de memoria (segmento) asignado a un
 * proceso en particular.
 */
typedef char segmentT[SEGMENT_SIZE];

/*
 * Tipo de datos: taskT
 * --------------------
 * Estructura que encapsula la informacion necesaria para controlar un
 * proceso.
 */
typedef struct taskT {
	int pid; 		/* process ID */
	int priority;	/* prioridad */
	int rounds;		/* ciclos del cpu que le quedan */
	int ppid; 		/* parent process ID */
	statusT status; 	/* estado  */
	int sp; 		/* stack pointer */
	int heap;       /* puntero al inicio del heap */
	int currheap;   /* puntero al lugar alocado hasta el momento */
	unsigned int tty; 	/* terminal asociada */
	int is_bkg; 		/* si es background*/
	char *cmd;		/* nombre del comando asociado al proceso */
	int next_pid; 		/* puntero al siguiente proceso (lista) */
	unsigned int waitpid;	/* Pid que esta esperando en caso de estar
				   en el estado WAITCHILD */
	int child_status;	/* Valor de retorno que debe completar el hijo
				   al morir si se esta en el estado WAITCHILD */
	unsigned int ticks;	/* Utilizado por el sleep. */
} taskT;

/*
 * Funcion: scheduler
 * ------------------
 * Ejecuta el programador de tareas, que se encarga de pasar el proceso
 * actual al estado de listo, seleccionar el proximo a ejecutar y realizar
 * el "context switch" entre ambos.
 */
int scheduler(void);

/*
 * Funcion: initialize_multitasking
 * --------------------------------
 * Inicializa variables del sistema necesarias para el multitasking.
 */
int initialize_multitasking(void);

/*
 * Funcion: new_task
 * -----------------
 * Crea un nuevo proceso del programa prg con argumentos de linea de comandos
 * argc y argv.
 */
unsigned int new_task(programT prg, int argc, char *argv[], int is_bkg);

/*
 * Funciones: exit_task, free_task
 * -------------------------------
 * free_task termina un proceso con el valor de retorno status.
 * exit_task es identica pero se aplica al proceso ctual.
 */
int free_task(unsigned int pid, int status);
void exit_task(int status);


/*
 * Funcion: get_task_by_pid
 * ------------------------
 * Devuelve un puntero al proceso (taskT) del pid dado.
 */
taskT *get_task_by_pid(int pid);

/*
 * Funcion: get_tak_pid
 * --------------------
 * Recibe un puntero a una estructura taskT y devuelve su PID.
 * Si el puntero es NULL, se asume el proceso actual.
 */
int get_task_pid(taskT *t);

/*
 * Funcion: set_status
 * -------------------
 * Asigna el estado (de multitasking) del proceso actual.
 */
void set_status(statusT status);

/*
 * Funcion: scancode_arrived
 * -------------------------
 * Esta rutina sirve para que el modulo que maneja la entrada estandar
 * desbloquee al proceso foreground de la terminal actual.
 */
void scancode_arrived(void);

/*
 * Funcion: get_next_task_pid
 * --------------------------
 * Permite iterar sobre la lista de procesos del sistema.
 */
int get_next_task_pid(int pid);

/*
 * Funciones: get_task_...
 * -----------------------
 * Las siguientes funciones devuelven atributos sobre el proceso del PID
 * dado. Si PID es 0, se asume el proceso actual.
 */
int get_task_ppid(int pid);
int get_task_prio(int pid);
int get_task_tty(int pid);
statusT get_task_status(int pid);
int is_bkg_task(int pid);
char *get_task_cmd(int pid);
int get_task_child_status();
void set_task_waitpid(unsigned int pid);
void set_task_ticks(unsigned int seconds);

/*
 * Funcion: incCurrHeap
 * -------------------
 * Aumenta el heap utilizado por el proceso del pid que se le pasa solamente si
 * se utiliza menos de el PAGE_SIZE despues de realizar el aumento.
 */
void * incCurrHeap(int size, int pid);

/*
 * Funcion: start_init
 * -------------------
 * Carga el primer proceso del sistema.
 * Esto evita que la lista de procesos de pueda quedar vacia.
 */
void start_init(void);

/*
 * Funcion: show_multitasker
 * -------------------
 * Funcion utilizada para mostrar los procesos y sus estados en la barra de abajo
 * en el shell
 */
void show_multitasker(void);

/*
 * Funcion: get_pid_status
 * -------------------
 * Devuelve un string con el estado que ocupa el lugar i-1 en el vector de
 * procesos
 */
char *get_pid_status(int i);

/*
 * Funcion: task_exists
 * -------------------
 * Devuelve el pid del proceso que ejecuta el comando cmd en la consola tty.
 */
int task_exists(char *cmd, unsigned int tty);

/*
 * Funcion: task_to_fg
 * -------------------
 * Vuelve a foreground la tarea cuyo comando es el que recibe, si es que existe
 * en la tty actual.
 */
int task_to_fg(char * cmd);

/*
 * Funcion: siginthandler
 * -------------------
 * Termina el proceso que se esta ejecutando en el momento en la tty donde se
 * recibe, si el proceso esta en foreground y no es el shell
 */
void siginthandler();

/*
 * Funciones: pageUp, pageDown
 * -----------------------
 * Reciben el pid del proceso cuyas paginas de stack y heap hay que bajar o
 * levantar.
 */
void pageUp(int pid);
void pageDown(int pid);

/*
 * Funcion: print_page_info
 * -----------------------
 * Muestra en pantalla informacion acerca de las paginas
 */
void print_page_info(void);

/*
 * Funcion: set_schedule_priority
 * -----------------------
 * Setea si se realiza el schedule con prioridades o no.
 * 1 con prioridades
 * 0 round robin
 */
void set_schedule_priority(int priority);

/*
 * Funcion: get_schedule_priority
 * -----------------------
 * Devuelve el tipo de scheduling que se este utilizando en ese momento.
 * 1 con prioridades
 * 0 round robin
 */
int get_schedule_priority(void);

#endif /* _SCHEDULER_H */

